//将html解析为ast语法树

//将<div id="app">hello</div>解析为
/*
{
  tag:'div',
  attrs:[
    {name:'id',value:'app'}
  ],
  children:[
    {tag:null,text:'hello'}
  ]
}
*/
const ncname = "[a-zA-Z_][\\-\\.0-9_a-zA-Z]*"; //标签名称
const qnameCapture = "((?:" + ncname + "\\:)?" + ncname + ")";//匹配标签名 <span:xx>
const startTagOpen = new RegExp("^<" + qnameCapture);//<xxx/>
const endTag = new RegExp("^<\\/" + qnameCapture + "[^>]*>");//</xxx>
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; //id='app'
const startTagClose = /^\s*(\/?)>/;
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;//{{}}  插值表达式


//遍历
//创建ast语法树
function createASTElement(tag, attrs) {
  return {
    tag, //div
    attrs, //属性
    children: [], //子节点
    type: 1,
    parent: null,
  }
}
let root; //根元素
let createParent; //父元素
//数据结构 栈
let stack = []; //[div,h1]
function start(tag, attrs) {
  // console.log('开始的标签------', tag, attrs);
  let element = createASTElement(tag, attrs);
  if (!root) {
    root = element;
  }
  createParent = element
  stack.push(element)  //[div]
}
function charts(text) {
  // console.log('文本------', text);
  //空格
  text = text.replace(/\s/g, '')
  if (text) {
    createParent.children.push({
      type: 3,
      text,
      parent: createParent.tag
    })
  }
}
function end(tag) {
  // console.log('结束的标签------', tag);
  let element = stack.pop();
  createParent = stack[stack.length - 1];
  if (createParent) { //元素的闭合
    element.parent = createParent.tag
    createParent.children.push(element)
  }
}


export function parseHTML(html) {
  while (html) { //html 为空结束
    let textEnd = html.indexOf("<"); //0
    if (textEnd === 0) { //是标签
      // 匹配开始标签
      const startTagMatch = parseStartTag();

      if (startTagMatch) {
        start(startTagMatch.tagName, startTagMatch.attrs)
        continue
      }
      //结束标签
      let endTagMatch = html.match(endTag);
      if (endTagMatch) {
        advance(endTagMatch[0].length)
        end(endTagMatch[1])
        continue
      }
    }

    let text //有文本
    if (textEnd > 0) {
      //获取文本内容
      text = html.substring(0, textEnd)  //  hello
    }
    if (text) {
      advance(text.length) //  </div>
      charts(text)
    }
  }
  function parseStartTag() {

    const start = html.match(startTagOpen); //1结果  ['<div', 'div', index: 0, input: '<div id="app">hello</div>', groups: undefined]  2false
    if (start) {
      //创建ast语法树
      let match = {
        tagName: start[1],
        attrs: []
      }
      advance(start[0].length) //删除掉标签 -> id="app"></div>
      let attr
      let endTag
      //不是结尾标签
      while (!(endTag = html.match(startTagClose)) && (attr = html.match(attribute))) {
        //[' id="app"', 'id', '=', 'app', undefined, undefined, index: 0, input: ' id="app">hello</div>', groups: undefined] 
        match.attrs.push({ name: attr[1], value: attr[3] || attr[4] || attr[5] || true })
        advance(attr[0].length) //  >hello</div>
      }

      if (endTag) {
        advance(endTag[0].length) //  hello</div>
        return match;
      }
    }


  }
  function advance(n) {
    html = html.substring(n);
  }
  console.log('最终的ast语法树', root);
  return root;
}